﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Threading;
using System.IO;

namespace HTTPListener
{
    public class VVHttpListener : IDisposable
    {
        private HttpListener a_listener;
        private Thread a_listenerThread;
        private ManualResetEvent a_stop;        


        public VVHttpListener()
        { 
            a_stop = new ManualResetEvent(false);            
            a_listener = new HttpListener();
            a_listenerThread = new Thread(HandleRequests);
            a_listenerThread.Name = "Http listening thead";
        }

        public void Start(int port) 
        {
            if (!a_listener.IsListening)
            {               
                a_listener.Prefixes.Add(String.Format(@"http://+:{0}/", port));
                a_listener.Start();
                a_listenerThread.Start();                
            }
        }

        public void Dispose()
        { 
            Stop(); 
        }

        public void Stop()
        {
            if(!a_listenerThread.IsAlive)
                return;
            a_stop.Set();
            a_listenerThread.Join();            
            a_listener.Stop();
        }

        private void HandleRequests()
        {
            IAsyncResult context;

            while (a_listener.IsListening)
            {
                context = a_listener.BeginGetContext(EndContextReady, null);

                if (0 == WaitHandle.WaitAny(new[] { a_stop, context.AsyncWaitHandle }))
                {                  
                        break;                   
                }
            }

            
        }

        private void EndContextReady(IAsyncResult ar)
        {
            var context = a_listener.EndGetContext(ar);


            try
            {

                //string txt = string.Format("Received a http request from {0} on url {1}\n", context.Request.RemoteEndPoint.Address, context.Request.Url);
                //Console.WriteLine(txt);
                string body = null;                               


                if(context.Request.ContentLength64>0)
                    using (StreamReader r = new StreamReader(context.Request.InputStream, System.Text.Encoding.Default))
                    {
                        body = r.ReadToEnd();
                    }

                // // Optional: sending a response:
                //string responseString = "Successfully received a http-" + context.Request.HttpMethod + " request from " + 
                //    context.Request.RemoteEndPoint.Address + " at " + DateTime.Now.ToString() + " (local time). ";                 

                //byte[] buffer = Encoding.UTF8.GetBytes(responseString);

                //context.Response.ContentLength64 = buffer.Length;

                //using (System.IO.Stream output = context.Response.OutputStream)
                //{
                //    output.Write(buffer, 0, buffer.Length);                   
                //}

                OnRequestReceived(new HttpContentEventArgs(body, context.Request.Url, context.Request.RemoteEndPoint));
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e);
            }
            finally 
            {
                context.Response.Close();
            }           

        } 

        public void OnRequestReceived(HttpContentEventArgs eventArgs) 
        {
            if (RequestReceived != null) 
            {
                RequestReceived(this, eventArgs);
            }
        }
       
        public event EventHandler<HttpContentEventArgs> RequestReceived;

        public class HttpContentEventArgs : EventArgs 
        {
            public string Body { get; private set; }
            public Uri Url { get; private set; }
            public IPEndPoint RemoteEndPoint { get; private set; }

            public HttpContentEventArgs(string body, Uri url, IPEndPoint remoteUser) 
            {
                this.Body = body;
                this.Url = url;
                this.RemoteEndPoint = remoteUser;
            }
        }
    }

    
}
